
#include <iostream>
#include <winsock2.h>

#pragma comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
	//初始化WSA
	/*
	* int WSAStartup(WORD wVersionRequested, LPWSDATA lpWSAData)
	* wVersionRequested 程序员需要版本信息
	* lpWSAData			WSADATA的地址结构
	*/
	WORD sockVersion = MAKEWORD(2, 2); //版本号 前面的数为主版本 后面的数为付版本
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0) //调用WSAStartup()传参 成功时返回0
	{
		return 0;
	}

	//创建套接字
	/*
	* int socket(int domain, int type, int protocol)
	*							/----PF_INET    IPV4协议族
	*						   /-----PF_INET6	IPV6协议族
	* domain 套接字用到的协议族<------PF_LOCAL	本地通信的UNIX协议族
	*						   \-----PF_PACKET	底层套接字协议族
	*							\----PF_IPX		IPX Novall协议族
	*
	*						 /----SOCK_STREAM (TCP稳定连接)   数据不会丢失  按顺序发送 没有边界
	* type 套接字数据传输方式<
	*						 \----SOCK_DGRAM  (UDP不稳定连接) 数据会丢失 不按顺序发送 有边界 限制数据传输大小
	*
	*						 /----SOCK_STREAM 使用IPPROTO_TCP 连接
	* protocol 决定了传输协议<
	*						 \----SOCK_DGRAM  使用IPPROTO_UDP 连接
	*/
	SOCKET socke_O = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (socke_O == INVALID_SOCKET) //成功时返回文件描述符 失败返回-1
	{
		std::cout << "socket error !";
		return 0;
	}

	//绑定IP和端口
	/*
	* struct sockaddr_in
	* {
	*	sa_family_t		sin_family  地址族				参考socket()第一个参数
	*	uint16_t		sin_prot    16位TCP/UDP端口号	保存16位端口号 以网络字节保存
	*   struct in_addr	sin_addr    32位IP地址
	*	char			sin_zero[8] 不使用
	* }
	* struct in_addr
	* {
	*	in_addr_t		s_addr		32位IPv4地址
	* }
	*/
	sockaddr_in sin; //这个是结构体类型
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);
	sin.sin_addr.S_un.S_addr = INADDR_ANY; //INADDR_ANY自动分配地址


	/*
	* int bind(int sockfd, struct sockaddr * myaddr, socklen_t addrlen)
	* sockfd	要分配的地址信息(IP地址和端口号)的套接字文件描述符
	* sockaddr	存有地址信息和结构体变量地址值
	* addrlen	第二个结构体变量的长度
	*/
	if (bind(socke_O, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) //成功返回0 失败返回-1
	{
		printf("bind error !");
	}

	//开始监听
	/*
	* int listen(int sock, int backlog)
	* socke		进入等待的套接字文件描述符
	* backlog	等待队列的长度 可以使多少连接请求 最多5个
	*/
	if (listen(socke_O, 5) == SOCKET_ERROR)
	{
	  	std::cout << "listen error !";
		return 0;
	}

	//循环接收数据
	SOCKET sClient;
	sockaddr_in remoteAddr;
	int nAddrlen = sizeof(remoteAddr);
	char revData[255];
	while (true)
	{
		printf("等待连接...\n");
		/*
		* int accept(int sock, struct sockaddr * addr, socklen_t * addrlen)
		* sock		套接字文件描述符
		* addr		保存发起链接请求的客户端地址信息的变量地址值，调用函数传来的地址变量参数填入客户端地址长度	
		* addrlen   addr结构体的长度 但是存有长度的变量地址 函数调用完后 该变量即被填入客户端地址长度
		*/
		sClient = accept(socke_O, (SOCKADDR *)&remoteAddr, &nAddrlen);
		if (sClient == INVALID_SOCKET)
		{
			std::cout << "accept error !";
			continue;
		}
		while (true)
		{
			//windows I/O函数 read/recv
			/*
			* int recv(SOCKET s, const char * buf, int len, int flags)
			* s		表示接收的套接字
			* buf	保存数据的缓冲地址
			* len	接收的最大字节数
			* flags	接收数据时用到的选项信息
			*/
			if (recv(sClient, revData, 255, NULL) == SOCKET_ERROR)
			{
				std::cout << "等待客户连接"; break;
			}
			else
			{
				std::cout << "客户端发送数据为:" << revData << std::endl;
			}
		}
		closesocket(sClient);
	}
	closesocket(socke_O);
	WSACleanup();
	return 0;
}
